import type { Stats } from "fs";
import { logger } from "../logger";
import { IFileSystem, IConfig } from "./interface";
import { fsPromises } from "./service/operator";
import { filePathValidator } from "./service/validator";

export class FileSystem implements IFileSystem {
    config: IConfig;
    constructor(config: IConfig) {
        this.config = config;
    }

    async readFile(path: string): Promise<Buffer | boolean> {
        if (!(await this.validatePath(path))) {
            return false;
        }
        return await fsPromises.readFile(path);
    }

    async writeFile(path: string, data: string | Buffer): Promise<boolean> {
        if (!(await this.validatePath(path))) {
            return false;
        }
        await fsPromises.writeFile(path, data);
        return true;
    }

    async appendFile(path: string, data: string | Buffer): Promise<boolean> {
        if (!(await this.validatePath(path))) {
            return false;
        }
        await fsPromises.appendFile(path, data);
        return true;
    }

    async deleteFile(path: string): Promise<boolean> {
        if (!(await this.validatePath(path))) {
            return false;
        }
        await fsPromises.unlink(path);
        return true;
    }

    async createDirectory(path: string): Promise<boolean> {
        if (!(await this.validatePath(path))) {
            return false;
        }
        await fsPromises.mkdir(path, { recursive: true });
        return true;
    }

    async removeDirectory(path: string): Promise<boolean> {
        if (!(await this.validatePath(path))) {
            return false;
        }
        await fsPromises.rmdir(path, { recursive: true });
        return true;
    }

    async readDirectory(path: string): Promise<string[] | boolean> {
        if (!(await this.validatePath(path))) {
            return false;
        }
        return await fsPromises.readdir(path);
    }

    async renameItem(oldPath: string, newPath: string): Promise<boolean> {
        if (!(await this.validatePath(oldPath)) || !(await this.validatePath(newPath))) {
            return false;
        }
        await fsPromises.rename(oldPath, newPath);
        return true;
    }

    async getFileStatus(path: string): Promise<Stats> {
        if (!(await this.validatePath(path))) {
            return Promise.reject(new Error("Invalid path"));
        }
        return await fsPromises.stat(path);
    }

    async validatePath(path: string): Promise<boolean> {
        const result = await filePathValidator.validate(path, this.config);
        if (result.success) {
            return true;
        } else {
            logger.error(JSON.stringify(result.error?.messages));
            return false;
        }
    }
}
